#ifndef CVPRIMITIVEMEMORYMANAGER_H_INCLUDED
#define CVPRIMITIVEMEMORYMANAGER_H_INCLUDED

//predecl

//includes
#include <GL/glew.h>
#include <boost/unordered_map.hpp>
#include <boost/intrusive/list.hpp>
#include "../PrimitiveArray.h"
#include "../cvRenderlist.h"
#include "../cvIPrimitiveMemoryManager.h"
#include "Line.h"
#include "../../General/cvMemory.h"
#include <DebugAlloc.h>
#include <DebugAllocator.h>

namespace cvImmediateModeRenderer
{
	/** LineRender inputs */
	struct linerender_datainput_t
	{	// data
		void * pverticles;		//
		GLsizei verticle_cnt;
		// static const settings.
		static const GLsizei s_stride = sizeof(cvVert) + sizeof(RGBAf);
		static const GLint s_colorcomp = 4;
		static const GLenum s_colortype = GL_FLOAT;
	};

	/**
	 *	@class PrimitiveMemoryManager for line primitives.
	 *	@brief the class manages storgate for the read-write primitives (not nodes!)
	 *	and write-once rendering. There exists only single manager per primitive type.
	*/
	class LinePrimitiveMemoryManager : public cvRenderInterface::PrimitiveMemoryManager
	{
		public:
			LinePrimitiveMemoryManager();
			~LinePrimitiveMemoryManager();

			/// Reserves read-write storgate memory for a line
			virtual void * accuirePrimitive();
			/// Releases the read-write line
			virtual void releasePrimitive(void * prim);

			/// purge all primitives from memory.
			virtual void purge();


			/// #6 Node Transport stage memory managment

			/**
			 *	Initiates the process of transporting read-write lines from the
			 *	storgate buffers into rendering buffer.
			 *	For singleshot rendering, this is not required.
			 */
			virtual void beginTransport(size_t prims);

			/// Points the read-write primitive to be transported
			virtual void transportNode(void * prim);

			/// Returns write-only range where verticles can be writed.
			virtual void * getTransportRange(size_t & size);

			/// Finalizes the transport
			virtual void finalizeTransport();

			/// Returns linerender_datainput_t descibling the payload for the renderer.
			virtual void * getRenderInputs();


		private:
			static const size_t PRIMITIVESPERPAGE = 256;
			typedef cvRenderInterface::PrimitiveArray<line_struct, PRIMITIVESPERPAGE> primitivepage_t;

			typedef DebugAllocator<const std::pair<line_struct* const, primitivepage_t*> > debug_stl;
			typedef DebugAlloc<const std::pair<line_struct* const, primitivepage_t*> > debug_stl_alloc;

			/// Define map
			typedef boost::unordered_map
			<line_struct*, primitivepage_t*, boost::hash<line_struct*>, std::equal_to<line_struct*>,
			cvPoolAllocator<std::pair<line_struct*, primitivepage_t*> >::RAN> primitivemap_t;
			typedef primitivemap_t::iterator primitivemap_it_t;

			/// Define list of primitive pages
			typedef boost::intrusive::member_hook<cvRenderInterface::PrimitiveArrayBase,
			boost::intrusive::list_member_hook<>, &cvRenderInterface::PrimitiveArrayBase::m_hook> list_options_t;
			typedef boost::intrusive::list<cvRenderInterface::PrimitiveArrayBase, list_options_t> pagelist_t;
			typedef pagelist_t::iterator pagelist_it_t;

			typedef DebugAllocSettings<true, true, 128, 64, true, 256> debugsettings;
			typedef DebugAlloc<primitivepage_t, null_debugsettings> debug_alloc_page;
			typedef DebugAlloc<line_struct, null_debugsettings> debug_alloc_renderbuffer;


			struct pagelist_disposer
			{
				void operator() (cvRenderInterface::PrimitiveArrayBase * page);
			};

			static cvPool m_primitivepage_pool;
			static cvPool m_renderbuffer_pool;

			primitivemap_t m_usedslots;		// filled slots
			primitivemap_t m_freeslots;		// empty slots
			pagelist_t m_pagelist;			// pagelist

			size_t m_renderbuffer_size;		// render buffer size.
			line_struct * m_renderbuffer;	// render buffer storgate
			line_struct * m_renderbuffer_write;		// pointer to where next write happens
			line_struct * m_read_begin;			// copy chunk begin
			size_t  m_read_repl;				// copy lenght.
			linerender_datainput_t m_renderinputs;

			void __init_primitivepage();
			void __reserve_renderbuffer(size_t prims);
	};


};
#endif // CVPRIMITIVEMEMORYMANAGER_H_INCLUDED
